package com.zenithmind.chat.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zenithmind.chat.mapper.ChatPrivateSessionMapper;
import com.zenithmind.chat.pojo.entity.ChatPrivateSession;
import com.zenithmind.chat.pojo.vo.ChatPrivateSessionVO;
import com.zenithmind.chat.service.ChatPrivateSessionService;
import com.zenithmind.common.context.UserContext;
import com.zenithmind.common.exception.BusinessException;
import com.zenithmind.common.result.PageResult;
import com.zenithmind.common.utils.BeanCopyUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 私聊会话服务实现类
 * 
 * @author ZenithMind Team
 * @since 2025-01-09
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ChatPrivateSessionServiceImpl extends ServiceImpl<ChatPrivateSessionMapper, ChatPrivateSession> 
        implements ChatPrivateSessionService {

    @Override
    public PageResult<ChatPrivateSessionVO> getUserSessionPage(String userId, Integer pageNum, Integer pageSize) {
        Page<ChatPrivateSession> page = new Page<>(pageNum, pageSize);
        
        LambdaQueryWrapper<ChatPrivateSession> wrapper = new LambdaQueryWrapper<>();
        wrapper.and(w -> w.eq(ChatPrivateSession::getUser1Id, userId)
                         .or()
                         .eq(ChatPrivateSession::getUser2Id, userId))
               .and(w -> w.eq(ChatPrivateSession::getUser1IsDeleted, 0)
                          .or()
                          .eq(ChatPrivateSession::getUser2IsDeleted, 0))
               .orderByDesc(ChatPrivateSession::getLastMessageTime);
        
        IPage<ChatPrivateSession> result = page(page, wrapper);
        
        List<ChatPrivateSessionVO> voList = result.getRecords().stream()
            .map(session -> convertToVO(session, userId))
            .collect(Collectors.toList());
        
        return PageResult.of(voList, result.getTotal(), result.getCurrent(), result.getSize());
    }

    @Override
    public List<ChatPrivateSessionVO> getUserSessions(String userId) {
        LambdaQueryWrapper<ChatPrivateSession> wrapper = new LambdaQueryWrapper<>();
        wrapper.and(w -> w.eq(ChatPrivateSession::getUser1Id, userId)
                         .or()
                         .eq(ChatPrivateSession::getUser2Id, userId))
               .and(w -> w.eq(ChatPrivateSession::getUser1IsDeleted, 0)
                          .or()
                          .eq(ChatPrivateSession::getUser2IsDeleted, 0))
               .orderByDesc(ChatPrivateSession::getLastMessageTime);
        
        List<ChatPrivateSession> sessions = list(wrapper);
        
        return sessions.stream()
            .map(session -> convertToVO(session, userId))
            .collect(Collectors.toList());
    }

    @Override
    public ChatPrivateSessionVO getSessionByUserIds(String user1Id, String user2Id) {
        LambdaQueryWrapper<ChatPrivateSession> wrapper = new LambdaQueryWrapper<>();
        wrapper.and(w -> w.and(w1 -> w1.eq(ChatPrivateSession::getUser1Id, user1Id)
                                       .eq(ChatPrivateSession::getUser2Id, user2Id))
                         .or()
                         .and(w2 -> w2.eq(ChatPrivateSession::getUser1Id, user2Id)
                                      .eq(ChatPrivateSession::getUser2Id, user1Id)))
               .and(w -> w.eq(ChatPrivateSession::getUser1IsDeleted, 0)
                          .or()
                          .eq(ChatPrivateSession::getUser2IsDeleted, 0));
        
        ChatPrivateSession session = getOne(wrapper);
        
        return session != null ? convertToVO(session, user1Id) : null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String createOrGetSession(String user1Id, String user2Id) {
        if (Objects.equals(user1Id, user2Id)) {
            throw new BusinessException("不能与自己创建会话");
        }
        
        // 先查询是否已存在会话
        ChatPrivateSessionVO existingSession = getSessionByUserIds(user1Id, user2Id);
        if (existingSession != null) {
            return existingSession.getId();
        }
        
        // 创建新会话
        ChatPrivateSession session = new ChatPrivateSession();
        session.setUser1Id(user1Id);
        session.setUser2Id(user2Id);
        session.setUser1Name("用户" + user1Id); // 实际应该从用户服务获取
        session.setUser2Name("用户" + user2Id);
        session.setUser1UnreadCount(0);
        session.setUser2UnreadCount(0);
        session.setUser1IsTop(0);       
        session.setUser2IsTop(0);
        session.setUser1IsDisturbFree(0);
        session.setUser2IsDisturbFree(0);
        session.setUser1IsDeleted(0);
        session.setUser2IsDeleted(0);
        session.setCreateTime(LocalDateTime.now());
        
        save(session);
        
        log.info("创建私聊会话: {} <-> {}", user1Id, user2Id);
        return session.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateLastMessage(String sessionId, String messageId, String messageContent) {
        ChatPrivateSession session = getById(sessionId);
        if (session == null) {
            throw new BusinessException("会话不存在");
        }
        
        session.setLastMessageId(messageId);
        session.setLastMessageContent(messageContent);
        session.setLastMessageTime(LocalDateTime.now());
        
        boolean result = updateById(session);
        
        if (result) {
            log.debug("更新会话 {} 最后消息信息", sessionId);
        }
        
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateUserUnreadCount(String sessionId, String userId, Integer increment) {
        ChatPrivateSession session = getById(sessionId);
        if (session == null) {
            throw new BusinessException("会话不存在");
        }
        
        if (Objects.equals(session.getUser1Id(), userId)) {
            session.setUser1UnreadCount(Math.max(0, session.getUser1UnreadCount() + increment));
        } else if (Objects.equals(session.getUser2Id(), userId)) {
            session.setUser2UnreadCount(Math.max(0, session.getUser2UnreadCount() + increment));
        } else {
            throw new BusinessException("用户不属于该会话");
        }
        
        boolean result = updateById(session);
        
        if (result) {
            log.debug("更新会话 {} 用户 {} 未读数: {}", sessionId, userId, increment);
        }
        
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean clearUserUnreadCount(String sessionId, String userId) {
        return updateUserUnreadCount(sessionId, userId, -Integer.MAX_VALUE);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean setSessionTop(String sessionId, String userId, Boolean isTop) {
        ChatPrivateSession session = getById(sessionId);
        if (session == null) {
            throw new BusinessException("会话不存在");
        }
        
        Integer topValue = isTop ? 1 : 0;
        
        if (Objects.equals(session.getUser1Id(), userId)) {
            session.setUser1IsTop(topValue);
        } else if (Objects.equals(session.getUser2Id(), userId)) {
            session.setUser2IsTop(topValue);
        } else {
            throw new BusinessException("用户不属于该会话");
        }
        
        boolean result = updateById(session);
        
        if (result) {
            log.info("用户 {} {} 会话 {}", userId, isTop ? "置顶" : "取消置顶", sessionId);
        }
        
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean setSessionDisturbFree(String sessionId, String userId, Boolean isDisturbFree) {
        ChatPrivateSession session = getById(sessionId);
        if (session == null) {
            throw new BusinessException("会话不存在");
        }
        
        Integer disturbFreeValue = isDisturbFree ? 1 : 0;
        
        if (Objects.equals(session.getUser1Id(), userId)) {
            session.setUser1IsDisturbFree(disturbFreeValue);
        } else if (Objects.equals(session.getUser2Id(), userId)) {
            session.setUser2IsDisturbFree(disturbFreeValue);
        } else {
            throw new BusinessException("用户不属于该会话");
        }
        
        boolean result = updateById(session);
        
        if (result) {
            log.info("用户 {} {} 会话 {} 免打扰", userId, isDisturbFree ? "开启" : "关闭", sessionId);
        }
        
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteSession(String sessionId, String userId) {
        ChatPrivateSession session = getById(sessionId);
        if (session == null) {
            throw new BusinessException("会话不存在");
        }
        
        if (Objects.equals(session.getUser1Id(), userId)) {
            session.setUser1IsDeleted(1);
        } else if (Objects.equals(session.getUser2Id(), userId)) {
            session.setUser2IsDeleted(1);
        } else {
            throw new BusinessException("用户不属于该会话");
        }
        
        // 如果双方都删除了，则物理删除会话
        if (session.getUser1IsDeleted() == 1 && session.getUser2IsDeleted() == 1) {
            removeById(sessionId);
            log.info("物理删除会话 {}", sessionId);
        } else {
            updateById(session);
            log.info("用户 {} 删除会话 {}", userId, sessionId);
        }
        
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean restoreSession(String sessionId, String userId) {
        ChatPrivateSession session = getById(sessionId);
        if (session == null) {
            throw new BusinessException("会话不存在");
        }
        
        if (Objects.equals(session.getUser1Id(), userId)) {
            session.setUser1IsDeleted(0);
        } else if (Objects.equals(session.getUser2Id(), userId)) {
            session.setUser2IsDeleted(0);
        } else {
            throw new BusinessException("用户不属于该会话");
        }
        
        boolean result = updateById(session);
        
        if (result) {
            log.info("用户 {} 恢复会话 {}", userId, sessionId);
        }
        
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveDraft(String sessionId, String userId, String draftContent) {
        ChatPrivateSession session = getById(sessionId);
        if (session == null) {
            throw new BusinessException("会话不存在");
        }
        
        if (Objects.equals(session.getUser1Id(), userId)) {
            session.setUser1Draft(draftContent);
        } else if (Objects.equals(session.getUser2Id(), userId)) {
            session.setUser2Draft(draftContent);
        } else {
            throw new BusinessException("用户不属于该会话");
        }
        
        boolean result = updateById(session);
        
        if (result) {
            log.debug("用户 {} 保存会话 {} 草稿", userId, sessionId);
        }
        
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean clearDraft(String sessionId, String userId) {
        return saveDraft(sessionId, userId, null);
    }

    @Override
    public Integer countUserSessions(String userId) {
        LambdaQueryWrapper<ChatPrivateSession> wrapper = new LambdaQueryWrapper<>();
        wrapper.and(w -> w.eq(ChatPrivateSession::getUser1Id, userId)
                         .or()
                         .eq(ChatPrivateSession::getUser2Id, userId))
               .and(w -> w.eq(ChatPrivateSession::getUser1IsDeleted, 0)
                          .or()
                          .eq(ChatPrivateSession::getUser2IsDeleted, 0));
        
        return Math.toIntExact(count(wrapper));
    }

    @Override
    public Integer getTotalUnreadCount(String userId) {
        LambdaQueryWrapper<ChatPrivateSession> wrapper = new LambdaQueryWrapper<>();
        wrapper.and(w -> w.eq(ChatPrivateSession::getUser1Id, userId)
                         .or()
                         .eq(ChatPrivateSession::getUser2Id, userId))
               .and(w -> w.eq(ChatPrivateSession::getUser1IsDeleted, 0)
                          .or()
                          .eq(ChatPrivateSession::getUser2IsDeleted, 0));
        
        List<ChatPrivateSession> sessions = list(wrapper);
        
        return sessions.stream()
            .mapToInt(session -> {
                if (Objects.equals(session.getUser1Id(), userId)) {
                    return session.getUser1UnreadCount();
                } else {
                    return session.getUser2UnreadCount();
                }
            })
            .sum();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer cleanInvalidSessions(Integer days) {
        LocalDateTime expireTime = LocalDateTime.now().minusDays(days);
        
        LambdaQueryWrapper<ChatPrivateSession> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ChatPrivateSession::getUser1IsDeleted, 1)
               .eq(ChatPrivateSession::getUser2IsDeleted, 1)
               .lt(ChatPrivateSession::getUpdateTime, expireTime);
        
        List<ChatPrivateSession> invalidSessions = list(wrapper);
        
        if (!invalidSessions.isEmpty()) {
            remove(wrapper);
            log.info("清理 {} 个无效会话", invalidSessions.size());
            return invalidSessions.size();
        }
        
        return 0;
    }

    @Override
    public Object getSessionStatistics(String userId, String startTime, String endTime) {
        LambdaQueryWrapper<ChatPrivateSession> wrapper = new LambdaQueryWrapper<>();
        
        if (StringUtils.hasText(userId)) {
            wrapper.and(w -> w.eq(ChatPrivateSession::getUser1Id, userId)
                             .or()
                             .eq(ChatPrivateSession::getUser2Id, userId))
                   .and(w -> w.eq(ChatPrivateSession::getUser1IsDeleted, 0)
                              .or()
                              .eq(ChatPrivateSession::getUser2IsDeleted, 0));
        }
        
        if (StringUtils.hasText(startTime)) {
            wrapper.ge(ChatPrivateSession::getCreateTime, LocalDateTime.parse(startTime));
        }
        
        if (StringUtils.hasText(endTime)) {
            wrapper.le(ChatPrivateSession::getCreateTime, LocalDateTime.parse(endTime));
        }
        
        long totalSessions = count(wrapper);
        
        return new Object() {
            public final Long total = totalSessions;
            public final Long active = 0L;
            public final Long today = 0L;
            public final Long thisWeek = 0L;
        };
    }

    /**
     * 转换为VO对象
     */
    private ChatPrivateSessionVO convertToVO(ChatPrivateSession session, String currentUserId) {
        ChatPrivateSessionVO vo = BeanCopyUtils.copyBean(session, ChatPrivateSessionVO.class);
        
        // 设置对方用户信息
        if (Objects.equals(session.getUser1Id(), currentUserId)) {
            vo.setOtherUserId(session.getUser2Id());
            vo.setOtherUserName(session.getUser2Name());
            vo.setOtherUserAvatar(session.getUser2Avatar());
            vo.setUnreadCount(session.getUser1UnreadCount());
            vo.setIsTop(session.getUser1IsTop() == 1);
            vo.setIsDisturbFree(session.getUser1IsDisturbFree() == 1);
            vo.setDraft(session.getUser1Draft());
        } else {
            vo.setOtherUserId(session.getUser1Id());
            vo.setOtherUserName(session.getUser1Name());
            vo.setOtherUserAvatar(session.getUser1Avatar());
            vo.setUnreadCount(session.getUser2UnreadCount());
            vo.setIsTop(session.getUser2IsTop() == 1);
            vo.setIsDisturbFree(session.getUser2IsDisturbFree() == 1);
            vo.setDraft(session.getUser2Draft());
        }
        
        // 设置是否有草稿
        vo.setHasDraft(StringUtils.hasText(vo.getDraft()));
        
        return vo;
    }
}
